package session

import (
	"database/sql"
	"gitee.com/zhendliu/sorm/clause"
	"gitee.com/zhendliu/sorm/dialect"
	"gitee.com/zhendliu/sorm/parser"
	"gitee.com/zhendliu/sorm/schema"
	"github.com/pkg/errors"
	"github.com/spf13/cast"
	"strings"
)

// Find gets all eligible records
func (s *Session) Find(values interface{}) error {
	defer s.Clear()

	tableNames, err := s.getTableNamesFind()
	if err != nil {
		return err
	}

	table := s.RefTable()

	getField := parser.GetField(table.FieldNames, s.selectField, s.omitField)
	for _, tnameOwner := range tableNames {
		tname := parser.GetTableName(tnameOwner)
		db, ok := s.dbs[tname]
		if !ok { // 如果没有找到，就说明没有分表，就用默认的db
			db = s.db
		}

		s.clause.Set(clause.SELECT, tnameOwner, getField)
		sql, vars := s.clause.Build(clause.SELECT, clause.JOIN, clause.WHERE, clause.OR, clause.GROUPBY, clause.HAVING, clause.ORDERBY)
		err = s.queryDatabase(db.Db, db.Dia, sql, vars, values)
		if err != nil {
			return errors.Wrap(err, "find error")
		}
	}

	return nil
}

func (s *Session) getTableNamesFind() ([]string, error) {
	table := s.RefTable()

	if table.SubTableFile != "" {
		whereExp, values := s.clause.Get(clause.WHERE)
		if strings.Contains(whereExp, table.SubTableFile) {
			return s.getTableNamesFromSubTable(table, whereExp, values)
		} else {
			return s.getAllTableNames(table)
		}
	} else {
		return []string{table.Name}, nil
	}
}

func (s *Session) getTableNamesFromSubTable(table *schema.Schema, whereExp string, values []interface{}) ([]string, error) {
	timeIndex := strings.Index(whereExp, table.SubTableFile)
	questionMarks := strings.Count(whereExp[:timeIndex], "?")
	if questionMarks > len(values) {
		return nil, errors.New("获取表名失败")
	}
	tableName, err := s.GetTableFromTableAndSplitFiled(table.Name, values[questionMarks])
	if err != nil {
		return nil, errors.New("获取表名失败")
	}
	return []string{tableName}, nil
}

func (s *Session) getAllTableNames(table *schema.Schema) ([]string, error) {
	tableNames, err := s.GetTableFromNone(table.Name)
	if err != nil {
		return nil, errors.Wrap(err, "分表的策略不支持")
	}
	return tableNames, nil
}

func (s *Session) queryDatabase(db *sql.DB, dialector dialect.Dialect, sql string, vars []interface{}, values interface{}) error {
	ln, lnVal := s.clause.Get(clause.LIMIT)
	of, ofVal := s.clause.Get(clause.OFFSET)
	var limit, offset int
	if len(lnVal) != 0 {
		limit = cast.ToInt(lnVal[0])
	}

	if len(ofVal) != 0 {
		offset = cast.ToInt(ofVal[0])
	}

	if ln == "" && of == "" {
		err := s.Query(s.ctx, db, dialector, sql, vars, values)
		if err != nil {
			return errors.Wrap(err, "find error")
		}
	} else {
		err := s.QueryPagination(s.ctx, db, dialector, sql, vars, limit, offset, values)
		if err != nil {
			return errors.Wrap(err, "find error")
		}
	}

	return nil
}

/*// Find gets all eligible records
func (s *Session) Find(values interface{}) error {
	start := time.Now()
	defer func() {
		s.Clear()
		elapsed := time.Since(start)
		log.Infof("sql总时间 【 %s 】", parser.RoundDuration(elapsed))
	}()

	s.CallMethod(BeforeQuery, nil)
	var (
		tableNames []string
		err        error
	)

	table := s.RefTable()

	if table.SubTableFile != "" {
		whereExp, values := s.clause.Get(clause.WHERE)
		if strings.Contains(whereExp, table.SubTableFile) {
			timeIndex := strings.Index(whereExp, table.SubTableFile)
			questionMarks := strings.Count(whereExp[:timeIndex], "?")
			if questionMarks > len(values) {
				return errors.New("获取表名失败")
			}
			tableName, err := s.GetTableFromTableAndSplitFiled(table.Name, values[questionMarks])
			if err != nil {
				return errors.New("获取表名失败")
			}
			tableNames = append(tableNames, tableName)
		} else {
			// 如果没有,包含则要加载全部的表名,仅支持取模的方式
			tableNames, err = s.GetTableFromNone(table.Name)
			if err != nil {
				return errors.Wrap(err, "分表的策略不支持")
			}
		}
	} else {
		tableNames = append(tableNames, table.Name)
	}

	getField := parser.GetField(table.FieldNames, s.selectField, s.omitField)
	for _, tnameOwner := range tableNames {
		tname := parser.GetTableName(tnameOwner)
		db, ok := s.dbs[tname]
		if !ok { // 如果没有找到，就说明没有分表，就用默认的db
			db = s.db
		}

		s.clause.Set(clause.SELECT, tnameOwner, getField)
		sql, vars := s.clause.Build(clause.SELECT, clause.WHERE, clause.OR, clause.GROUPBY, clause.HAVING, clause.ORDERBY)
		ln, lnVal := s.clause.Get(clause.LIMIT)
		of, ofVal := s.clause.Get(clause.OFFSET)
		var limit, offset int
		if len(lnVal) != 0 {
			limit = cast.ToInt(lnVal[0])
		}

		if len(ofVal) != 0 {
			offset = cast.ToInt(ofVal[0])
		}

		if ln == "" && of == "" {
			err = s.Query(s.ctx, db.Db, sql, vars, values)
			if err != nil {
				return errors.Wrap(err, "find error")
			}
		} else {
			err = s.QueryPagination(s.ctx, db.Db, db.Dia, sql, vars, limit, offset, values)
			if err != nil {
				return errors.Wrap(err, "find error")
			}
		}

	}

	s.CallMethod(AfterQuery, nil)
	return nil
}*/
